#if defined(_WIN32) || defined(_WIN64)
#   define NOMINMAX
#endif
#include "../include/easylog.hpp"

const size_t THR_NUM = 3;
const size_t MSG_NUM = 100 * 10000;
const size_t MSG_LEN = 100;

void bench(const std::string& name, size_t th_num, size_t msg_num, size_t msg_len)
{
    auto logger = easylog::get(name);
    logger->get_sinkers()[0]->set_pattern("%m%n");

    printf("测试开始，日志共 %ld 条，单条大小 %ld Bytes，总大小 %ld KB\n\n",
           msg_num, msg_len, msg_num * msg_len / 1024);

    std::string msg(msg_len - 1, 'a'); // 生成日志的有效载荷

    size_t msg_num_per_th = msg_num / th_num; // 单个线程的日志输出条数

    std::vector<std::thread> thread_v;
    std::vector<double> cost_v(th_num);

    for (int i = 0; i < th_num; i++)
    {
        thread_v.emplace_back([&, i]()
            {
                auto start = std::chrono::high_resolution_clock::now();

                for (int j = 0; j < msg_num_per_th; j++) logger->info(msg);

                auto end = std::chrono::high_resolution_clock::now();

                std::chrono::duration<double> cost = end - start;
                cost_v[i] = cost.count();

                printf("线程%d：\t输出日志 %ld 条，耗时 %lf s\n", i, msg_num_per_th, cost_v[i]);
            }
        );
    }

    for (auto& th : thread_v)
        th.join();

    double cost = cost_v[0];
    for (auto e : cost_v) cost = std::min(cost, e);

    size_t msg_num_per_sec = msg_num / cost; // 每秒输出日志数量
    size_t size_per_sec = msg_num * msg_len / cost / 1024; // 每秒输出日志大小 KB

    printf("\n\t总耗时：%lf s\n", cost);
    printf("\t每秒输出日志条数 %ld 条\n", msg_num_per_sec);
    printf("\t每秒输出日志大小 %ld KB\n", size_per_sec);
}

void sync_bench()
{
    std::cout << "---------------- 同步日志性能测试 ----------------\n" << std::endl;

    easylog::logger_builder::ptr llb = std::make_shared<easylog::local_logger_builder>();
    llb->build_logger_type(easylog::logger_builder::sync);
    llb->build_logger_name("sync_bench");
    llb->build_limit_level();
#if defined (_WIN32) || defined (_WIN64)
    llb->build_sinker<easylog::file_sinker>("logfile\\bench_test_sync.log");
#else
    llb->build_sinker<easylog::file_sinker>("logfile/bench_test_sync.log");
#endif

    easylog::registry::instance().add(llb->build());

    //easylog::registry::instance().get("sync_bench")->set_always_flush(true);

    bench("sync_bench", THR_NUM, MSG_NUM, MSG_LEN);

    std::cout << std::endl;
}

void async_bench()
{
    std::cout << "---------------- 异步日志性能测试 ----------------\n" << std::endl;

    easylog::logger_builder::ptr llb = std::make_shared<easylog::local_logger_builder>();
    llb->build_logger_type(easylog::logger_type::async);
    llb->build_logger_name("async_bench");
#if defined (_WIN32) || defined (_WIN64)
    llb->build_sinker<easylog::file_sinker>("logfile\\bench_test_async.log");
#else
    llb->build_sinker<easylog::file_sinker>("logfile/bench_test_async.log");
#endif
    llb->build_work_type(easylog::worker_type::unsafe);
    llb->build_thread_num(1);
    llb->build_buffer_size(easylog::size_enum::m10KB);
    llb->build_buffer_increment(easylog::size_enum::m2KB);
    llb->build_buffer_threshold(easylog::size_enum::m20KB);

    easylog::registry::instance().add(llb->build());
    bench("async_bench", THR_NUM, MSG_NUM, MSG_LEN);

    std::cout << std::endl;
}

int main()
{
    sync_bench();
    async_bench();

    return 0;
}
